using System.Configuration;
using BoxBinary.AspectCache.Core.ConfigurationMappers;
using BoxBinary.AspectCache.Core.PolicyDefinition;

namespace BoxBinary.AspectCache.Core
{
    /// <summary>
    /// Represents a configuration section for controlling custom Cache settings.
    /// </summary>
    public class Configuration : ConfigurationSection
    {
        private static Configuration _section;
        private CachePolicySpecificationCollection _cachePolicySpecifications;
        private PolicyGovernanceDefaults _policyGovernanceDefaults;

        /// <summary>
        /// Provides access to the <code>cacheStateConfig</code> section of the current configuration file.
        /// </summary>
        public static Configuration Current
        {
            get
            {
                if (_section == null)
                    _section = (Configuration) ConfigurationManager.GetSection("aspectCache");
                return _section;
            }
        }

        /// <summary>
        /// <para>Gets or sets the path to the replication sink folder, which is the <code>cacheStateReplicationSinkPath</code> attribute of the configuration file.</para>
        /// <para>The default value is <value>~/App_Replicated/CacheManagement/BroadcastEventSink/</value></para>
        /// <para>The following characters are disallowed: <value> !@#$%^&*()[]{};'"|</value></para>
        /// </summary>
        [StringValidator(InvalidCharacters = " !@#$%^&*()[]{};'\"|"),
         ConfigurationProperty("cacheStateReplicationSinkPath",
             DefaultValue = "~/App_Replicated/CacheManagement/BroadcastEventSink/",
             IsKey = false, IsRequired = false)]
        public string CacheStateReplicationSinkPath
        {
            get { return ((string) (base["cacheStateReplicationSinkPath"])); }
            set { base["cacheStateReplicationSinkPath"] = value; }
        }

        /// <summary>
        /// <para>Gets or sets the path to the disk persistence folder, which is the <code>cacheItemDiskPersistencePath</code> attribute of the configuration file.</para>
        /// <para>The default value is <value>~/App_TemporaryFiles/CacheManagement/DiskPersistence/</value></para>
        /// <para>The following characters are disallowed: <value> !@#$%^&*()[]{};'"|</value></para>
        /// </summary>
        [StringValidator(InvalidCharacters = " !@#$%^&*()[]{};'\"|"),
         ConfigurationProperty("cacheItemDiskPersistencePath",
             DefaultValue = "~/App_TemporaryFiles/CacheManagement/DiskPersistence/",
             IsKey = false, IsRequired = false)]
        public string CacheItemDiskPersistencePath
        {
            get { return ((string) (base["cacheItemDiskPersistencePath"])); }
            set { base["cacheItemDiskPersistencePath"] = value; }
        }

        /// <summary>
        /// <para>Gets or sets the path to the permanent disk persistence folder, which is the <code>cacheItemPermanentDiskPersistencePath</code> attribute of the configuration file.</para>
        /// <para>The default value is <value>~/App_TemporaryFiles/CacheManagement/PermanentDiskPersistence/</value></para>
        /// <para>The following characters are disallowed: <value> !@#$%^&*()[]{};'"|</value></para>
        /// </summary>
        [StringValidator(InvalidCharacters = " !@#$%^&*()[]{};'\"|"),
         ConfigurationProperty("cacheItemPermanentDiskPersistencePath",
             DefaultValue = "~/App_TemporaryFiles/CacheManagement/PermanentDiskPersistence/",
             IsKey = false, IsRequired = false)]
        public string CacheItemPermanentDiskPersistencePath
        {
            get { return ((string) (base["cacheItemPermanentDiskPersistencePath"])); }
            set { base["cacheItemPermanentDiskPersistencePath"] = value; }
        }

        /// <summary>
        /// <para>Gets or sets whether cache broadcast events (i.e. replication) are enabled, which is the <code>enableCacheStateReplicationSink</code> attribute of the configuration file.</para>
        /// <para>The default value is <value>false</value></para>
        /// </summary>
        [ConfigurationProperty("enableCacheStateReplicationSink", DefaultValue = false, IsKey = false,
            IsRequired = false)]
        public bool EnableCacheStateReplicationSink
        {
            get { return ((bool) (base["enableCacheStateReplicationSink"])); }
            set { base["enableCacheStateReplicationSink"] = value; }
        }

        /// <summary>
        /// <para>Gets or sets whether cache broadcast events (i.e. replication) are logged, which is the <code>enableReplicationSinkMonitorLog</code> attribute of the configuration file.</para>
        /// <para>The default value is <value>false</value></para>
        /// </summary>
        [ConfigurationProperty("enableReplicationSinkMonitorLog", DefaultValue = false, IsKey = false,
            IsRequired = false)]
        public bool EnableReplicationSinkMonitorLog
        {
            get { return ((bool) (base["enableReplicationSinkMonitorLog"])); }
            set { base["enableReplicationSinkMonitorLog"] = value; }
        }

        [ConfigurationProperty("policyGovernanceDefaults")]
        public PolicyGovernanceDefaults PolicyGovernanceDefaults
        {
            get
            {
                if (_policyGovernanceDefaults == null)
                {
                    _policyGovernanceDefaults = base["policyGovernanceDefaults"] as PolicyGovernanceDefaults;
                }
                return _policyGovernanceDefaults;
            }
        }

        /// <summary>
        /// Gets a collection of <see cref="CachePolicySpecification"/> objects from the <code>cacheCategories</code> attribute of the configuration file.
        /// </summary>
        [ConfigurationProperty("cachePolicies")]
        public CachePolicySpecificationCollection CachePolicySpecifications
        {
            get
            {
                if (_cachePolicySpecifications == null)
                {
                    _cachePolicySpecifications = (CachePolicySpecificationCollection)base["cachePolicies"];
                    //lock (_cachePolicySpecifications)
                    //{

                    //    if (_cachePolicySpecifications.Count == 0)
                    //    {
                    //        _cachePolicySpecifications.Add(GenerateDefaultCacheCategory());
                    //        _cachePolicySpecifications.Add(
                    //            new CachePolicySpecification("soapResults",
                    //                              CacheItemFootprint.MediumCreationExpense | CacheItemFootprint.LowHeapRequirement |
                    //                              CacheItemFootprint.MediumChangeFrequency));
                    //        _cachePolicySpecifications.Add(
                    //            new CachePolicySpecification("searchResults",
                    //                              CacheItemFootprint.LowCreationExpense | CacheItemFootprint.MediumHeapRequirement |
                    //                              CacheItemFootprint.HighChangeFrequency));
                    //    }
                    //}
                }
                return _cachePolicySpecifications;
            }
        }

        internal static CachePolicySpecification GenerateDefaultCacheCategory()
        {
            return new CachePolicySpecification("default",
                                     CacheItemFootprint.MediumCreationExpense |
                                     CacheItemFootprint.MediumHeapRequirement |
                                     CacheItemFootprint.MediumChangeFrequency);
        }
    }
}